package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.comment.service.CommentHotService;
import com.heima.comment.service.CommentRepayService;
import com.heima.comment.service.CommentService;
import com.heima.common.exception.CustException;
import com.heima.feigns.ArticleFeign;
import com.heima.feigns.UserFeign;
import com.heima.feigns.WemediaFeign;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApAuthor;
import com.heima.model.comment.dtos.*;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.pojos.ApCommentRepay;
import com.heima.model.comment.pojos.ApCommentRepayLike;
import com.heima.model.comment.vos.ApCommentVo;
import com.heima.model.common.constants.article.HotArticleConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.app.NewBehaviorDTO;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.wemedia.dtos.CommentManagerDTO;
import com.heima.model.wemedia.dtos.CommentManagerIdDTO;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.model.wemedia.vos.CommentManagerRepVo;
import com.heima.model.wemedia.vos.CommentManagerVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CommentServiceImpl implements CommentService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private UserFeign userFeign;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    WemediaFeign wemediaFeign;

    /**
     * 根据 文章id 查询评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByArticleId(CommentDTO dto) {
        //1 参数检查
        if (dto == null || dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        Integer size = dto.getSize();
        if (size == null || size <= 0) {
            size = 10;
        }
        // 判断是否
        //2 查询Mongo文章所有评论列表
        List<ApComment> apCommentList;
        // 文章评论的首页
        if (dto.getIndex().intValue() == 1) {
            //查询置顶评论
            Query query = Query.query(Criteria.where("articleId").is(dto.getArticleId()).and("flag").is(3)).with(Sort.by(Sort.Direction.DESC, "likes"));
            apCommentList = mongoTemplate.find(query, ApComment.class);
            //查询热点评论  5
            Query query2 = Query.query(Criteria.where("articleId").is(dto.getArticleId()).and("flag").is(1)).with(Sort.by(Sort.Direction.DESC, "likes"));
//            apCommentList = mongoTemplate.find(query, ApComment.class);
            apCommentList.addAll(mongoTemplate.find(query, ApComment.class));
            // 热点集合不为空
            if (CollectionUtils.isNotEmpty(apCommentList)) {
                size = size - apCommentList.size();
                List<ApComment> normalComments = mongoTemplate.find(getQuery(dto, size), ApComment.class);
                apCommentList.addAll(normalComments);
            } else {
                apCommentList = mongoTemplate.find(
                        getQuery(dto, size),
                        ApComment.class
                );
            }
        } else {
            apCommentList = mongoTemplate.find(
                    getQuery(dto, size),
                    ApComment.class
            );
        }
        //3 封装查询结果
        //3.1 用户未登录 直接返回评论列表
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.okResult(apCommentList);
        }
        //3.2 用户登录，需要加载当前用户对评论点赞的列表
        // 获取文章对应的所有评论ID列表
        List<String> idList = apCommentList.stream()
                .map(ApComment::getId)
                .collect(Collectors.toList());
        // 查询 点赞批量列表 按照评论id 筛选
        List<ApCommentLike> apCommentLikes = mongoTemplate.find(
                Query.query(Criteria.where("commentId").in(idList)
                        .and("authorId").is(user.getId()))
                , ApCommentLike.class);
        // 遍历当前用户点赞列表 和当前评论列表
        if (CollectionUtils.isNotEmpty(apCommentList)
                && CollectionUtils.isNotEmpty(apCommentLikes)) {
            // 获取点过赞的评论id
            List<String> commentIds = apCommentLikes.stream()
                    .map(ApCommentLike::getCommentId).collect(Collectors.toList());
            // 遍历评论列表，将comment 转为 commentVO
            return ResponseResult.okResult(apCommentList.stream()
                    .map(comment -> parseCommentVO(comment, commentIds)));
        }
        // 发送新行为消息
        NewBehaviorDTO newBehavior = new NewBehaviorDTO();
        newBehavior.setType(NewBehaviorDTO.BehaviorType.COMMENT);
        newBehavior.setArticleId(dto.getArticleId());
        newBehavior.setAdd(1);
        newBehavior.setCreateTime(LocalDate.now().toString());
        newBehavior.setUserId(user.getId());
        rabbitTemplate.convertAndSend(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_QUEUE, JSON.toJSONString(newBehavior));
        log.info("成功发送 文章阅读行为消息 , 消息内容: {}", newBehavior);
        return ResponseResult.okResult(apCommentList);
    }

    /**
     * 将comment 转为 vo对象   根据likes情况判断是否点过赞
     *
     * @param apComment
     * @param commentIds
     * @return
     */
    private ApCommentVo parseCommentVO(ApComment apComment, List<String> commentIds) {
        ApCommentVo apCommentVo = new ApCommentVo();
        BeanUtils.copyProperties(apComment, apCommentVo);
        //遍历当前用户点赞列表
        if (commentIds.contains(apCommentVo.getId())) {
            apCommentVo.setOperation((short) 0);
        }
        return apCommentVo;
    }

    /**
     * 构建查询条件
     */
    private Query getQuery(CommentDTO dto, Integer size) {
        return Query.query(Criteria.where("articleId").is(dto.getArticleId())
                .and("flag").is(0).and("createdTime").lt(dto.getMinDate()))
                .limit(size).with(Sort.by(Sort.Direction.DESC, "createdTime"));
    }

    @Override
    public ResponseResult saveComment(CommentSaveDTO dto) {
        //1.检查参数 (validated校验)
        //2.判断是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //3.安全过滤,自行实现
        //4.保存评论
        ResponseResult<ApUser> apUserResult = userFeign.findUserById(user.getId());
        if (apUserResult.getCode() != 0 || apUserResult.getData() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "当前登录信息有误");
        }
        user = apUserResult.getData();
        ApComment apComment = new ApComment();
        apComment.setAuthorId(user.getId());
        apComment.setAuthorName(user.getName());
        apComment.setImage(user.getImage());
        apComment.setContent(dto.getContent());
        apComment.setArticleId(dto.getArticleId());
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());
        apComment.setLikes(0);
        apComment.setReply(0);
        apComment.setType((short) 0);
        apComment.setFlag((short) 0);
        mongoTemplate.save(apComment);
        return ResponseResult.okResult();
    }

    @Autowired
    CommentHotService commentHotService;

    @Autowired
    RedissonClient redisson;

    /**
     * 点赞评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentLikeDTO dto) {
        //1 参数检查 (Validated校验)
        //2 判断用户登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        RLock lock = redisson.getLock("likes-lock");
        lock.lock();
        ApComment apComment;
        try {
            //3 查询评论
            apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
            if (apComment == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
            }
            // 用户不能重复点赞
            ApCommentLike apCommentLike = mongoTemplate.findOne(
                    Query.query(Criteria.where("authorId").is(user.getId())
                            .and("commentId").is(dto.getCommentId())
                    ),
                    ApCommentLike.class);
            Short operation = dto.getOperation();
//        if (apCommentLike != null && operation.intValue() == 0) {
//            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "已点赞");
//        }
            //点赞
            if (operation.intValue() == 0) {
                // 点赞+1
                apComment.setLikes(apComment.getLikes() + 1);
                mongoTemplate.save(apComment);
                // 保存评论点赞信息
                apCommentLike = new ApCommentLike();
                apCommentLike.setAuthorId(user.getId());
                apCommentLike.setCommentId(apComment.getId());
                apCommentLike.setOperation(dto.getOperation());
                mongoTemplate.save(apCommentLike);
                //计算热点评论评论
                if (apComment.getLikes() >= 10 && apComment.getFlag().shortValue() == 0) {
                    commentHotService.hotCommentExecutor(apComment);
                }
            } else {
                // 取消点赞
                apComment.setLikes(
                        apComment.getLikes() <= 0 ? 0 : apComment.getLikes() - 1);
                mongoTemplate.save(apComment);
                //删除点赞评论信息
                mongoTemplate.remove(Query.query(Criteria.
                        where("authorId").is(user.getId())
                        .and("commentId").is(apComment.getId())), ApCommentLike.class);
            }
        } finally {
            lock.unlock();
        }
        //4 数据返回
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("likes", apComment.getLikes());
        return ResponseResult.okResult(resultMap);
    }

    @Autowired
    ArticleFeign articleFeign;

    //自媒体评论管理
    @Override
    public ResponseResult commentManager(CommentManagerDTO dto) {
        //获取当前登录用户
        ApUser wmUser2 = AppThreadLocalUtils.getUser();
        if (wmUser2 == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer wmUserId = wmUser2.getId();
        //查询WmUser
        ResponseResult<WmUser> wmUserResp = wemediaFeign.findById(wmUserId + "");
        if (!wmUserResp.checkCode()) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "当前用户没有开通自媒体账户!");
        }
        WmUser user = wmUserResp.getData();
        //根据apuserId查询作者
        ResponseResult<ApAuthor> apAuthorResp = articleFeign.findByUserId(user.getApUserId());
        if (!apAuthorResp.checkCode()) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "当前用户的作者信息不存在!");
        }
        //获取作者信息
        ApAuthor apAuthor = apAuthorResp.getData();
        //根据作者id查询所有文章列表
        ResponseResult<List<ApArticle>> listResponseResult = articleFeign.articleByAuthorId(apAuthor.getId() + "");
        if (listResponseResult.checkCode()) {
            List<ApArticle> aparticleList = listResponseResult.getData();
            //检查参数
            if (dto.getSize() == null || dto.getSize() == 0) {
                dto.setSize(5);
            }
            Integer size = dto.getSize();
            //创建评论集合保存查询到的评论对象
            List<ApComment> apCommentList = new ArrayList<>();
            //根据当前文章查询所有文章的评论,按照时间降序排列
            for (ApArticle apArticle : aparticleList) {
                Query query = Query.query(Criteria.where("articleId").is(apArticle.getId()));
                Sort sort = Sort.by(Sort.Direction.DESC, "creataTime");
                List<ApComment> apComments = mongoTemplate.find(query, ApComment.class);
                //将查询到的数据添加到集合
                apCommentList.addAll(apComments);
            }
            //判断
            if (apCommentList.size() == 0) {
                CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "当前没有评论数据!");
            }
            //截取集合中最新的size条评论数据
            List<CommentManagerVo> commentManagerVoList = apCommentList.stream().sorted((a, b) -> {
                return (int) b.getCreatedTime().getTime() - (int) a.getCreatedTime().getTime();
            }).map(newApComment -> {
                //查询当前回复的点赞量
                Query commentQuery = Query.query(Criteria.where("commentId").is(newApComment.getId()));
                List<ApCommentLike> apCommentLikes = mongoTemplate.find(commentQuery, ApCommentLike.class);
                //创建CommentManagerVo
                CommentManagerVo commentManagerVo = new CommentManagerVo();
                commentManagerVo.setDate(newApComment.getCreatedTime());
                commentManagerVo.setContent(newApComment.getContent());
                commentManagerVo.setAdmireNum(apCommentLikes.size());  //评论的点赞量
                commentManagerVo.setCommentId(newApComment.getId());
                //查询当前评论的回复数据
                Query commentRepayQuery = Query.query(Criteria.where("commentId").is(newApComment.getId()));
                List<ApCommentRepay> apCommentRepays = mongoTemplate.find(commentRepayQuery, ApCommentRepay.class);
                if (apCommentRepays.size() > 0) {
                    //创建集合保存回复数据
                    ArrayList<CommentManagerRepVo> apCommentRepayList = new ArrayList<>();
                    for (ApCommentRepay apCommentRepay : apCommentRepays) {
                        //根据回复人id查询信息
                        ResponseResult<WmUser> wmUserResp2 = wemediaFeign.findByApUserId(apCommentRepay.getAuthorId() + "");
                        if (wmUserResp2.checkCode()) {
                            WmUser wmUser = wmUserResp2.getData();
                            //创建CommentManagerRepVo
                            CommentManagerRepVo commentManagerRepVo = new CommentManagerRepVo();
                            commentManagerRepVo.setNickName(wmUser.getName());
                            commentManagerRepVo.setContent(apCommentRepay.getContent());
                            apCommentRepayList.add(commentManagerRepVo);
                        }
                    }
                    //将apCommentRepayList放到commentManagerVo
                    commentManagerVo.setReplies(apCommentRepayList);
                }
                return commentManagerVo;
            }).limit(size).collect(Collectors.toList());
            if (commentManagerVoList.size() > 0) {
                //删除之前的数据,将新数据保存到mongo
                Query query = Query.query(Criteria.where("id").gte("0"));
                mongoTemplate.remove(query, CommentManagerVo.class);
                int id = 0;
                for (CommentManagerVo commentManagerVo : commentManagerVoList) {
                    id++;
                    commentManagerVo.setId(id + "");
                    mongoTemplate.save(commentManagerVo);
                }
                return ResponseResult.okResult(commentManagerVoList);
            }
        }
        return ResponseResult.okResult();
    }

    //评论点赞
    @Override
    public ResponseResult liking(CommentManagerIdDTO dto) {
        String id = dto.getId();
        //获取登录用户
        ApUser wmUser = AppThreadLocalUtils.getUser();
        if (wmUser == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //查询所有评论管理数据
        List<CommentManagerVo> commentManagerVoList = mongoTemplate.findAll(CommentManagerVo.class);
        for (CommentManagerVo commentManagerVo : commentManagerVoList) {
            if (commentManagerVo.getId().equals(id)) {
                //组装like方法参数对象
                CommentLikeDTO commentLikeDTO = new CommentLikeDTO();
                commentLikeDTO.setCommentId(commentManagerVo.getCommentId());
                commentLikeDTO.setOperation((short) 0);
                like(commentLikeDTO);
                return ResponseResult.okResult();
            }
        }
        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "评论不存在!!");
    }

    @Autowired
    CommentRepayService commentRepayService;

    //评论回复
    @Override
    public ResponseResult add(CommentManagerRepayDTO dto) {
        String id = dto.getId();
        //获取登录用户
        ApUser wmUser = AppThreadLocalUtils.getUser();
        if (wmUser == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //查询所有评论管理数据
        List<CommentManagerVo> commentManagerVoList = mongoTemplate.findAll(CommentManagerVo.class);
        for (CommentManagerVo commentManagerVo : commentManagerVoList) {
            if (commentManagerVo.getId().equals(id)) {
                CommentRepaySaveDTO commentRepaySaveDTO = new CommentRepaySaveDTO();
                commentRepaySaveDTO.setCommentId(commentManagerVo.getCommentId());
                commentRepaySaveDTO.setContent(dto.getContent());
                commentRepayService.saveCommentRepay(commentRepaySaveDTO);
            }
        }
        return ResponseResult.okResult();
    }

    //评论置顶
    @Override
    public ResponseResult changeTop(CommentManagerIdDTO dto) {
        String id = dto.getId();
        //获取登录用户
        ApUser wmUser = AppThreadLocalUtils.getUser();
        if (wmUser == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //查询所有评论管理数据
        List<CommentManagerVo> commentManagerVoList = mongoTemplate.findAll(CommentManagerVo.class);
        String id2 = null;  //保存需要置顶的评论的id
        boolean flag = false;
        int count = 0;  //置顶评论数量计数
        for (CommentManagerVo commentManagerVo : commentManagerVoList) {
            if (commentManagerVo.getId().equals(id)) {
                id2 = commentManagerVo.getCommentId();
                break;
            }
        }
        List<ApComment> apCommentList = mongoTemplate.findAll(ApComment.class);
        for (ApComment apComment : apCommentList) {
            if (apComment.getFlag() == (short) 3) {
                count++;
            }
        }
        if (count > 2) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "当前置顶数已经有3个,不能新增置顶!");
        }
        //根据评论id查询评论表
        for (ApComment apComment : apCommentList) {
            if (apComment.getId().equals(id2)) {
                //修改评论状态
                apComment.setFlag((short) 3);
                //保存回数据库
                mongoTemplate.save(apComment);
                return ResponseResult.okResult();
            }
        }
        return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
    }

    //删除评论
    @Override
    public ResponseResult delete(CommentManagerIdDTO dto) {
        String id = dto.getId();
        //获取登录用户
        ApUser wmUser = AppThreadLocalUtils.getUser();
        if (wmUser == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //查询所有评论管理数据
        List<CommentManagerVo> commentManagerVoList = mongoTemplate.findAll(CommentManagerVo.class);
        for (CommentManagerVo commentManagerVo : commentManagerVoList) {
            if (commentManagerVo.getId().equals(id)) {
                //删除评论数据
                Query query = Query.query(Criteria.where("_id").is(commentManagerVo.getCommentId()));
                mongoTemplate.remove(query, ApComment.class);
                //查询对应的评论回复信息,并删除评论回复和评论点赞
                Query query2 = Query.query(Criteria.where("commentId").is(commentManagerVo.getCommentId()));
                ApCommentRepay apCommentRepay = mongoTemplate.findOne(query2, ApCommentRepay.class);
                mongoTemplate.remove(query2, ApCommentLike.class);
                mongoTemplate.remove(query2, ApCommentRepay.class);
                //删除回复点赞
                Query query3 = Query.query(Criteria.where("commentRepayId").is(apCommentRepay.getId()));
                mongoTemplate.remove(query3, ApCommentRepayLike.class);
                //响应结果
                return ResponseResult.okResult();
            }
        }
        return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
    }
}
